
# 从 qtpy 库的 QtWidgets 模块导入所需的类
from qtpy.QtWidgets import QWidget
from qtpy.QtWidgets import QHBoxLayout
from qtpy.QtWidgets import QMenu

# 从 PyFlow 核心模块的 Common 中导入所有内容
from src.Core.Common import *

# 定义一个全局字典，用于存储 UI 输入小部件引脚的工厂函数
UI_INPUT_WIDGET_PINS_FACTORIES = {}

class IInputWidget(object):
    """
    输入小部件的基类，定义了输入小部件应实现的基本接口。
    """
    def __init__(self,parent= None):
        """
        初始化 IInputWidget 实例。

        :param parent: 父对象，默认为 None。
        """
        super(IInputWidget, self).__init__()

    def widgetVariant(self):
        """
        返回小部件的变体类型。

        :return: 小部件变体类型，默认为 "DefaultWidget"。
        """
        return "DefaultWidget"

    def getWidget(self):
        """
        获取小部件实例。此方法需要在子类中实现。

        :raises NotImplementedError: 如果在子类中未实现该方法，则抛出此异常。
        """
        raise NotImplementedError("getWidget of IInputWidget is not implemented")

    def setWidget(self, widget):
        """
        设置小部件实例。此方法需要在子类中实现。

        :param widget: 要设置的小部件实例。
        :raises NotImplementedError: 如果在子类中未实现该方法，则抛出此异常。
        """
        raise NotImplementedError("setWidget of IInputWidget is not implemented")

    def blockWidgetSignals(self, bLock=False):
        """
        阻止或允许小部件发出信号。此方法需要在子类中实现。

        :param bLock: 是否阻止信号，默认为 False。
        :raises NotImplementedError: 如果在子类中未实现该方法，则抛出此异常。
        """
        raise NotImplementedError(
            "blockWidgetSignals of IInputWidget is not implemented"
        )

class InputWidgetRaw(QWidget, IInputWidget):
    """
    此类型的小部件可作为由设计器生成的复杂 UI 的基类。
    """

    def __init__(self, parent=None, dataSetCallback=None, defaultValue=None, **kwargs):
        """
        初始化 InputWidgetRaw 实例。

        :param parent: 父对象，默认为 None。
        :param dataSetCallback: 用于将数据设置到引脚的回调函数，签名为 void(object)，默认为 None。
        :param defaultValue: 小部件的默认值，默认为 None。
        :param kwargs: 其他关键字参数。
        """
        super(InputWidgetRaw, self).__init__(parent=parent)
        self._defaultValue = defaultValue
        # 函数签名为 void(object)，用于将数据设置到引脚
        self.dataSetCallback = dataSetCallback
        self._widget = None
        # 创建一个上下文菜单
        self._menu = QMenu()
        # 为菜单添加一个 "ResetValue" 动作
        self.actionReset = self._menu.addAction("ResetValue")
        # 连接动作的触发信号到 onResetValue 方法
        self.actionReset.triggered.connect(self.onResetValue)

    def setWidgetValueNoSignals(self, pin):
        """
        在不发出信号的情况下设置小部件的值。

        :param pin: 引脚对象。
        """
        self.blockWidgetSignals(True)
        self.setWidgetValue(pin.currentData())
        self.blockWidgetSignals(False)

    def setWidget(self, widget):
        """
        设置小部件实例。

        :param widget: 要设置的小部件实例。
        """
        self._widget = widget

    def getWidget(self):
        """
        获取小部件实例，确保小部件不为 None。

        :return: 小部件实例。
        :raises AssertionError: 如果小部件为 None，则抛出此异常。
        """
        assert self._widget is not None
        return self._widget

    def onResetValue(self):
        """
        重置小部件的值为默认值。
        """
        self.setWidgetValue(self._defaultValue)

    def setWidgetValue(self, value):
        """
        将值设置到小部件中。此方法可在子类中重写。

        :param value: 要设置的值。
        """
        """to widget"""
        pass

    def widgetValueUpdated(self, value):
        """
        当小部件的值更新时调用。此方法可在子类中重写。

        :param value: 更新后的值。
        """
        """from widget"""
        pass

    def contextMenuEvent(self, event):
        """
        处理上下文菜单事件，显示上下文菜单。

        :param event: 上下文菜单事件对象。
        """
        self._menu.exec_(event.globalPos())

class InputWidgetSingle(InputWidgetRaw):
    """
    此类型的小部件用于简单的小部件，如按钮、复选框等。
    它由一个水平布局的小部件本身和一个重置按钮组成。
    """

    def __init__(self, parent=None, dataSetCallback=None, defaultValue=None, **kwargs):
        """
        初始化 InputWidgetSingle 实例。

        :param parent: 父对象，默认为 None。
        :param dataSetCallback: 用于将数据设置到引脚的回调函数，签名为 void(object)，默认为 None。
        :param defaultValue: 小部件的默认值，默认为 None。
        :param kwargs: 其他关键字参数。
        """
        super(InputWidgetSingle, self).__init__(
            parent=parent,
            dataSetCallback=dataSetCallback,
            defaultValue=defaultValue,
            **kwargs,
        )
        # 创建一个水平布局并设置到当前小部件
        self.horizontalLayout = QHBoxLayout(self)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self._index = 0
        self._widget = None
        self.senderPin = None

    def getWidget(self):
        """
        获取小部件实例，调用父类的 getWidget 方法。

        :return: 小部件实例。
        """
        return InputWidgetRaw.getWidget(self)

    def setWidget(self, widget):
        """
        设置小部件实例，并将其插入到水平布局中。

        :param widget: 要设置的小部件实例。
        """
        InputWidgetRaw.setWidget(self, widget)
        self.horizontalLayout.insertWidget(self._index, self.getWidget())

def REGISTER_UI_INPUT_WIDGET_PIN_FACTORY(packageName, factory):
    """
    注册 UI 输入小部件引脚的工厂函数。

    :param packageName: 包名，作为字典的键。
    :param factory: 工厂函数，作为字典的值。
    """
    if packageName not in UI_INPUT_WIDGET_PINS_FACTORIES:
        UI_INPUT_WIDGET_PINS_FACTORIES[packageName] = factory

def createInputWidget(
    dataType,
    dataSetter,
    defaultValue=None,
    widgetVariant=DEFAULT_WIDGET_VARIANT,
    **kwargs,
):
    """
    根据注册的工厂函数创建输入小部件。

    :param dataType: 数据类型。
    :param dataSetter: 数据设置器函数。
    :param defaultValue: 默认值，默认为 None。
    :param widgetVariant: 小部件变体类型，默认为 DEFAULT_WIDGET_VARIANT。
    :param kwargs: 其他关键字参数。
    :return: 创建的输入小部件实例，如果未找到合适的工厂函数则返回 None。
    """
    pinInputWidget = None
    for packageName, factory in UI_INPUT_WIDGET_PINS_FACTORIES.items():
        pinInputWidget = factory(
            dataType, dataSetter, defaultValue, widgetVariant, **kwargs
        )
        if pinInputWidget is not None:
            return pinInputWidget
    return pinInputWidget